﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Windows;
using DotNetNeural.BackPropagation;
using DotNetNeural.Data.Clusters;
using DotNetNeural.Perceptron.Algorithm;
using DotNetNeural.Projections;
using DotNetNeural.Research;
using DotNetNeural.Scaling;
using DotNetNeural.Utils;

namespace ClusterGenerator
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {

            InitializeComponent();


            CryptoRandom rnd = new CryptoRandom();

            for (int i = 0; i < 500; ++i)
            {
                Console.WriteLine((int)rnd.NextDouble(96 - 10, 96 + 10) + ",");
            }

            //Loaded += new RoutedEventHandler(MainWindow_Loaded);

            NewMethod();

            //OldTests();
        }

        void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            float[,] m1 = new float[100, 300];
            float[,] m2 = new float[100, 300];
            float[,] res = new float[100, 300];

            Random rnd = new Random();

            for (int i = 0; i < 100; ++i)
            {
                for (int j = 0; j < 300; ++j)
                {
                    m1[i, j] = (float)rnd.NextDouble();
                    m2[i, j] = (float)rnd.NextDouble();
                }
            }

            Stopwatch s = new Stopwatch();

            s.Start();

            for (int k = 0; k < 100; ++k)
            {
                for (int i = 0; i < 100; ++i)
                {
                    for (int j = 0; j < 300; ++j)
                    {
                        res[i, j] = 0;
                        for (int l = 0; l < 100; ++l) // OR k<b.GetLength(0)
                            res[i, j] = res[i, j] + m1[i, l] * m2[l, j];
                    }
                }
            }

            s.Stop();
        }

        private static void NewMethod()
        {
            const int clustersCount = 5;
            const int itemsInCluster = 50;
            const int inputsCount = 100;

            TrainingSetSettings settings = new TrainingSetSettings()
            {
                ClustersCount = clustersCount,
                ControlItemsInClusterRatio = 0.3f,
                InputsCount = inputsCount,
                MinItemsInCluster = itemsInCluster,
                MaxItemsInCluster = itemsInCluster,
                DistanceBetweenClusters = 30,
                Scale = new LinearScale(0f, 1f)
            };

            
            TrainingSetGenerator generator = new TrainingSetGenerator();
            var trainingSet = generator.CreateTrainingSet(settings);

            //debug
            //KohonenProjection projection = new KohonenProjection(trainingSet.LearningItems.Select(i => i.Input), 2);
            //var points = projection.CalculateProjection();
            //foreach (var point in points)
            //{
            //    Console.WriteLine( "{" + String.Format("{0},{1}",
            //        point.X.ToString(CultureInfo.InvariantCulture.NumberFormat),
            //        point.Y.ToString(CultureInfo.InvariantCulture.NumberFormat)) + "},");
            //}

            //LipschitzCalculator calc = new LipschitzCalculator();
            //calc.CalculateLipschitzConstant(trainingSet);

            IPerceptron perceptron = new MultilayerPreceptron(inputsCount, 5);
            perceptron.AddLayer(40);
            perceptron.InitWeights(MultilayerPreceptron.DefaultSettings);

            //IBackPropagation b = new BackPropagationAlgorithm((c) =>
            //    {
            //        Console.WriteLine(c.DeviationValue);
            //    });
            Stopwatch s = new Stopwatch();

            IBackPropagation b = new BackPropagationAlgorithm((dv) =>
            {
                Debug.WriteLine(dv.Deviation.Deviation);
            });

            s.Start();

            b.BackPropagate(perceptron, trainingSet);

            s.Stop();

            Console.WriteLine(String.Format("Time: {0}", s.Elapsed));
        }

        private static void OldTests()
        {
            var g = new VectorGenerator();
            var list = g.GenereateDistant(7, 50, 10, 0, 100);

            List<Cluster> clusters = new List<Cluster>();
            var cg = new DotNetNeural.Utils.ClusterGenerator();

            foreach (var cc in list)
            {
                var c = cg.Generate(cc, 10, 20);
                clusters.Add(c);
            }

            var clusterVectors = clusters.SelectMany(c => c);


            var sprojection = new KohonenProjection(clusterVectors.ToList(), 100 /*, new RectilinearMetric()*/);
            var prj = sprojection.CalculateProjection();

            foreach (var point in prj)
            {
                Console.WriteLine(String.Format("|{0},{1};,",
                    point.X.ToString(CultureInfo.InvariantCulture.NumberFormat),
                    point.Y.ToString(CultureInfo.InvariantCulture.NumberFormat)));
            }

            //var exp = new ExpressionHelper().CreateExpression();
            //var r = exp(2.7f);

            IPerceptron p = new MultilayerPreceptron(3, 2);
            p.AddLayer(3);
            p.AddLayer(5);
            p.AddLayer(4);
            p.InitWeights(MultilayerPreceptron.DefaultSettings);

            var expectedOutput = new float[2] { 0.9f, 0.2f };
            var expectedOutput2 = new float[2] { 0.2f, 0.9f };
            var input = new float[3] { 0.1f, 0.9f, 0.1f };
            var input2 = new float[3] { 0.9f, 0.1f, 0.9f };

            //BackPropagationAlgorithm a = new BackPropagationAlgorithm();
            //for (int i = 0; i < 100000; ++i)
            //{
            //    a.BackPropagate(p, input, expectedOutput);
            //    a.BackPropagate(p, input2, expectedOutput2);
            //}

            //var newO = p.Propagate(input);
            //var newO2 = p.Propagate(input2);


            //var clusterCenters = new VectorGenerator().GenereateDistant(115, 5, 6, 0, 10);

            //var clusterCentre = new VectorGenerator().Generate(3, 1, 9);

            //var cluster = new DotNetNeural.Utils.ClusterGenerator().Generate(clusterCentre, 10, 0.5f);

            //string str = new XmlSerializer().ToXml(cluster).ToString();

            //var cluster2 = new XmlSerializer().ClusterFromXml(str);

            //FVector v1 = new FVector() { 1f, 1f };
            //FVector v2 = new FVector() { 1f, 2f };

            //MetricsHelper m = new MetricsHelper();

            //float d = m.CalculateEuclidDistance(v1, v2);
        }
    }
}
